forked from blender/blender
WIP: uv-simple-select #1
@ -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"
|
||||
}
|
@ -236,6 +236,8 @@ ForEachMacros:
|
||||
- LOOP_UNSELECTED_POINTS
|
||||
- LOOP_VISIBLE_KEYS
|
||||
- LOOP_VISIBLE_POINTS
|
||||
- LIGHT_FOREACH_BEGIN_DIRECTIONAL
|
||||
- LIGHT_FOREACH_BEGIN_LOCAL
|
||||
- LISTBASE_CIRCULAR_BACKWARD_BEGIN
|
||||
- LISTBASE_CIRCULAR_FORWARD_BEGIN
|
||||
- LISTBASE_FOREACH
|
||||
|
@ -524,7 +524,7 @@ endif()
|
||||
if(NOT APPLE)
|
||||
option(WITH_CYCLES_DEVICE_HIP "Enable Cycles AMD HIP support" ON)
|
||||
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(CYCLES_HIP_BINARIES_ARCH)
|
||||
endif()
|
||||
@ -625,8 +625,10 @@ mark_as_advanced(
|
||||
|
||||
# Vulkan
|
||||
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(
|
||||
WITH_VULKAN_BACKEND
|
||||
WITH_VULKAN_GUARDEDALLOC
|
||||
)
|
||||
|
||||
# Metal
|
||||
|
@ -299,7 +299,11 @@ else
|
||||
ifneq ("$(wildcard $(DEPS_BUILD_DIR)/build.ninja)","")
|
||||
DEPS_BUILD_COMMAND:=ninja
|
||||
else
|
||||
ifeq ($(OS), Darwin)
|
||||
DEPS_BUILD_COMMAND:=make -s
|
||||
else
|
||||
DEPS_BUILD_COMMAND:="$(BLENDER_DIR)/build_files/build_environment/linux/make_deps_wrapper.sh" -s
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
@ -398,7 +402,7 @@ endif
|
||||
|
||||
deps: .FORCE
|
||||
@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)" \
|
||||
-B"$(DEPS_BUILD_DIR)" \
|
||||
|
@ -22,7 +22,7 @@ elseif(UNIX AND NOT APPLE)
|
||||
)
|
||||
endif()
|
||||
|
||||
# Boolean crashes with Arm assembly, see T103423.
|
||||
# Boolean crashes with Arm assembly, see #103423.
|
||||
if(BLENDER_PLATFORM_ARM)
|
||||
set(GMP_OPTIONS
|
||||
${GMP_OPTIONS}
|
||||
|
74
build_files/build_environment/linux/make_deps_wrapper.sh
Executable file
74
build_files/build_environment/linux/make_deps_wrapper.sh
Executable 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" "$@"
|
@ -85,7 +85,7 @@ if(NOT APPLE)
|
||||
set(WITH_CYCLES_DEVICE_OPTIX 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_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_ONEAPI_BINARIES ON CACHE BOOL "" FORCE)
|
||||
endif()
|
||||
|
@ -544,7 +544,7 @@ endfunction()
|
||||
function(setup_platform_linker_libs
|
||||
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)
|
||||
target_link_libraries(${target} ${JEMALLOC_LIBRARIES})
|
||||
endif()
|
||||
|
@ -440,7 +440,7 @@ string(APPEND PLATFORM_LINKFLAGS " -stdlib=libc++")
|
||||
# Make stack size more similar to Embree, required for Embree.
|
||||
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_CXX_ARCHIVE_CREATE "<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>")
|
||||
# llvm-ranlib doesn't support this flag. Xcode's libtool does.
|
||||
|
@ -121,7 +121,7 @@ if(WITH_WINDOWS_BUNDLE_CRT)
|
||||
include(InstallRequiredSystemLibraries)
|
||||
|
||||
# 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})
|
||||
string(FIND ${lib} "ucrtbase" pos)
|
||||
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.
|
||||
NOT WITH_WINDOWS_SCCACHE AND # And not when sccache is enabled
|
||||
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()
|
||||
|
||||
# Add each of our libraries to our cmake_prefix_path so find_package() could work
|
||||
|
@ -38,7 +38,7 @@ PROJECT_NAME = Blender
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# 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
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
@ -476,7 +476,7 @@ MODULE_GROUPING = {
|
||||
|
||||
# -------------------------------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_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":
|
||||
# SHA1 Git hash
|
||||
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_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,
|
||||
)
|
||||
|
||||
return "Undocumented, consider `contributing <https://developer.blender.org/T51061>`__."
|
||||
return "Undocumented, consider `contributing <https://developer.blender.org/>`__."
|
||||
|
||||
|
||||
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.
|
||||
|
||||
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)
|
||||
with open(filepath, "w", encoding="utf-8") as fh:
|
||||
|
@ -1676,15 +1676,18 @@ class CyclesPreferences(bpy.types.AddonPreferences):
|
||||
col.label(text="and NVIDIA driver version %s or newer" % driver_version,
|
||||
icon='BLANK1', translate=False)
|
||||
elif device_type == 'HIP':
|
||||
if True:
|
||||
col.label(text="HIP temporarily disabled due to compiler bugs", icon='BLANK1')
|
||||
else:
|
||||
import sys
|
||||
if sys.platform[:3] == "win":
|
||||
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,
|
||||
icon='BLANK1', translate=False)
|
||||
elif sys.platform.startswith("linux"):
|
||||
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',
|
||||
translate=False)
|
||||
elif device_type == 'ONEAPI':
|
||||
|
@ -20,7 +20,7 @@ class CyclesPresetPanel(PresetPanel, Panel):
|
||||
@staticmethod
|
||||
def post_cb(context):
|
||||
# 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.filter_size = render.filter_size
|
||||
|
||||
|
@ -105,11 +105,12 @@ GPUShader *BlenderFallbackDisplayShader::bind(int width, int height)
|
||||
|
||||
/* Bind shader now to enable uniform assignment. */
|
||||
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];
|
||||
size[0] = width;
|
||||
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_;
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ BlenderImageLoader::BlenderImageLoader(BL::Image b_image,
|
||||
: b_image(b_image),
|
||||
frame(frame),
|
||||
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. */
|
||||
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;
|
||||
}
|
||||
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. */
|
||||
PointerRNA colorspace_ptr = b_image.colorspace_settings().ptr;
|
||||
metadata.colorspace = get_enum_identifier(colorspace_ptr, "name");
|
||||
|
@ -24,7 +24,7 @@ void BlenderSync::sync_light(BL::Object &b_parent,
|
||||
Light *light = light_map.find(key);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Update if either object or light data changed. */
|
||||
|
@ -94,7 +94,7 @@ void python_thread_state_restore(void **python_thread_state)
|
||||
*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);
|
||||
if (result) {
|
||||
@ -131,8 +131,8 @@ static PyObject *init_func(PyObject * /*self*/, PyObject *args)
|
||||
}
|
||||
|
||||
PyObject *path_coerce = nullptr, *user_path_coerce = nullptr;
|
||||
path_init(PyC_UnicodeAsByte(path, &path_coerce),
|
||||
PyC_UnicodeAsByte(user_path, &user_path_coerce));
|
||||
path_init(PyC_UnicodeAsBytes(path, &path_coerce),
|
||||
PyC_UnicodeAsBytes(user_path, &user_path_coerce));
|
||||
Py_XDECREF(path_coerce);
|
||||
Py_XDECREF(user_path_coerce);
|
||||
|
||||
|
@ -404,7 +404,7 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
|
||||
* 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
|
||||
* (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) {
|
||||
free_blender_memory_if_possible();
|
||||
|
@ -766,7 +766,7 @@ void BlenderSync::free_data_after_sync(BL::Depsgraph &b_depsgraph)
|
||||
(BlenderSession::headless || is_interface_locked) &&
|
||||
/* Baking re-uses the depsgraph multiple times, clearing crashes
|
||||
* 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() &&
|
||||
/* Persistent data must main caches for performance and correctness. */
|
||||
!is_persistent_data;
|
||||
|
@ -42,12 +42,15 @@ endif()
|
||||
###########################################################################
|
||||
|
||||
if(WITH_CYCLES_HIP_BINARIES AND WITH_CYCLES_DEVICE_HIP)
|
||||
find_package(HIP)
|
||||
set_and_warn_library_found("HIP compiler" HIP_FOUND WITH_CYCLES_HIP_BINARIES)
|
||||
set(WITH_CYCLES_HIP_BINARIES OFF)
|
||||
message(STATUS "HIP temporarily disabled due to compiler bugs")
|
||||
|
||||
if(HIP_FOUND)
|
||||
message(STATUS "Found HIP ${HIP_HIPCC_EXECUTABLE} (${HIP_VERSION})")
|
||||
endif()
|
||||
# find_package(HIP)
|
||||
# set_and_warn_library_found("HIP compiler" HIP_FOUND WITH_CYCLES_HIP_BINARIES)
|
||||
|
||||
# if(HIP_FOUND)
|
||||
# message(STATUS "Found HIP ${HIP_HIPCC_EXECUTABLE} (${HIP_VERSION})")
|
||||
# endif()
|
||||
endif()
|
||||
|
||||
if(NOT WITH_HIP_DYNLOAD)
|
||||
|
@ -906,7 +906,7 @@ bool HIPDevice::should_use_graphics_interop()
|
||||
* possible, but from the empiric measurements it can be considerably slower than using naive
|
||||
* 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
|
||||
HIPContextScope scope(this);
|
||||
|
||||
|
@ -51,7 +51,7 @@ static inline bool hipSupportsDevice(const int hipDevId)
|
||||
hipDeviceGetAttribute(&major, hipDeviceAttributeComputeCapabilityMajor, hipDevId);
|
||||
hipDeviceGetAttribute(&minor, hipDeviceAttributeComputeCapabilityMinor, hipDevId);
|
||||
|
||||
return (major >= 10);
|
||||
return (major >= 9);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@ -586,7 +586,7 @@ void MetalDevice::erase_allocation(device_memory &mem)
|
||||
if (it != metal_mem_map.end()) {
|
||||
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) {
|
||||
device_ptr *pointers = (device_ptr *)&launch_params;
|
||||
pointers[mmem->pointer_index] = 0;
|
||||
|
@ -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
|
||||
* (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()) {
|
||||
/* 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;
|
||||
}
|
||||
|
||||
if (resolution_divider <= pixel_size_) {
|
||||
/* When resolution divider is at or below pixel size, schedule one sample. This doesn't effect
|
||||
* the sample count at this resolution division, but instead assists in the calculation of
|
||||
* the resolution divider. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
/* Schedule samples equal to the resolution divider up to a maximum of 4.
|
||||
* The idea is to have enough information on the screen by increasing the sample count as the
|
||||
* resolution is decreased. */
|
||||
/* NOTE: Changing this formula will change the formula in
|
||||
* `RenderScheduler::calculate_resolution_divider_for_time()`. */
|
||||
return min(max(1, resolution_divider / pixel_size_), 4);
|
||||
}
|
||||
|
||||
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
|
||||
* 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
|
||||
* simple and compute device is fast). */
|
||||
start_resolution_divider_ = max(resolution_divider_for_update, pixel_size_);
|
||||
/* Don't let resolution drop below the desired one. It's better to be slow than provide an
|
||||
* unreadable viewport render. */
|
||||
start_resolution_divider_ = min(resolution_divider_for_update,
|
||||
default_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)
|
||||
{
|
||||
/* 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
|
||||
* 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;
|
||||
return ceil_to_int(sqrt(navigation_samples * ratio_between_times));
|
||||
}
|
||||
|
||||
int calculate_resolution_divider_for_resolution(int width, int height, int resolution)
|
||||
|
@ -412,11 +412,12 @@ if(WITH_CYCLES_CUDA_BINARIES)
|
||||
# warn for other versions
|
||||
if((CUDA_VERSION STREQUAL "101") OR
|
||||
(CUDA_VERSION STREQUAL "102") OR
|
||||
(CUDA_VERSION_MAJOR STREQUAL "11"))
|
||||
(CUDA_VERSION_MAJOR STREQUAL "11") OR
|
||||
(CUDA_VERSION_MAJOR STREQUAL "12"))
|
||||
else()
|
||||
message(WARNING
|
||||
"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()
|
||||
|
||||
# build for each arch
|
||||
@ -514,6 +515,16 @@ if(WITH_CYCLES_CUDA_BINARIES)
|
||||
else()
|
||||
message(STATUS "CUDA binaries for ${arch} require CUDA 10 or earlier, skipped.")
|
||||
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)
|
||||
message(STATUS "CUDA binaries for ${arch} require CUDA 10.0+, skipped.")
|
||||
elseif(${arch} MATCHES ".*_8.")
|
||||
|
@ -686,7 +686,7 @@ ccl_device_inline Spectrum bsdf_albedo(ccl_private const ShaderData *sd,
|
||||
albedo *= ((ccl_private const PrincipledSheenBsdf *)sc)->avg_value;
|
||||
break;
|
||||
case CLOSURE_BSDF_HAIR_PRINCIPLED_ID:
|
||||
albedo *= bsdf_principled_hair_albedo(sc);
|
||||
albedo *= bsdf_principled_hair_albedo(sd, sc);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
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;
|
||||
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
|
||||
|
@ -10,7 +10,7 @@
|
||||
#ifndef WITH_CYCLES_OPTIMIZED_KERNEL_AVX2
|
||||
# define KERNEL_STUB
|
||||
#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)))
|
||||
# define __KERNEL_SSE__
|
||||
# define __KERNEL_SSE2__
|
||||
|
@ -10,7 +10,7 @@
|
||||
#ifndef WITH_CYCLES_OPTIMIZED_KERNEL_SSE2
|
||||
# define KERNEL_STUB
|
||||
#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)))
|
||||
# define __KERNEL_SSE2__
|
||||
# endif
|
||||
|
@ -10,7 +10,7 @@
|
||||
#ifndef WITH_CYCLES_OPTIMIZED_KERNEL_SSE41
|
||||
# define KERNEL_STUB
|
||||
#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)))
|
||||
# define __KERNEL_SSE2__
|
||||
# define __KERNEL_SSE3__
|
||||
|
@ -645,7 +645,7 @@ ccl_device_inline void kernel_gpu_film_convert_half_write(ccl_global uchar4 *rgb
|
||||
const int y,
|
||||
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__
|
||||
ccl_global half *out = ((ccl_global half *)rgba) + (rgba_offset + y * rgba_stride + x) * 4;
|
||||
out[0] = half_pixel.x;
|
||||
|
@ -394,7 +394,7 @@ bool OSLShaderManager::osl_compile(const string &inputfile, const string &output
|
||||
|
||||
/* 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;
|
||||
thread_scoped_lock lock(osl_compiler_mutex);
|
||||
|
||||
|
@ -573,7 +573,7 @@ void ShaderManager::device_update_common(Device * /*device*/,
|
||||
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();
|
||||
}
|
||||
|
@ -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
|
||||
* without any "gaps".
|
||||
* 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 ||
|
||||
tile_params.window_width != tile_params.width ||
|
||||
tile_params.window_height != tile_params.height) {
|
||||
|
@ -421,7 +421,7 @@ ccl_device_inline float fast_expf(float x)
|
||||
|
||||
#if !defined(__KERNEL_GPU__) && !defined(_MSC_VER)
|
||||
/* 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. */
|
||||
ccl_device float4 fast_exp2f4(float4 x)
|
||||
{
|
||||
|
@ -516,7 +516,7 @@ GHOST_TSuccess GHOST_ContextCGL::releaseNativeHandles()
|
||||
|
||||
/* 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 OSType METAL_CORE_VIDEO_PIXEL_FORMAT = kCVPixelFormatType_32BGRA;
|
||||
|
@ -141,7 +141,7 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
|
||||
/* -------------------------------------------------------------------- */
|
||||
#else
|
||||
/* 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();
|
||||
#endif /* USE_GLXEW_INIT_WORKAROUND */
|
||||
|
||||
|
@ -302,7 +302,7 @@ bool GHOST_NDOFManager::setDevice(ushort vendor_id, ushort product_id)
|
||||
switch (product_id) {
|
||||
case 0xC62E: /* Plugged in. */
|
||||
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;
|
||||
hid_map_button_num_ = 2;
|
||||
|
@ -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.
|
||||
* 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
|
||||
@ -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
|
||||
* (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
|
||||
*/
|
||||
#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.
|
||||
* \note This is similar to X11 workaround by the same name, see: T47228.
|
||||
* 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: #47228.
|
||||
*/
|
||||
#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.
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
|
||||
@ -1442,7 +1442,7 @@ static GHOST_TKey xkb_map_gkey(const xkb_keysym_t sym)
|
||||
|
||||
/* 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);
|
||||
|
||||
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
|
||||
* 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
|
||||
* 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
|
||||
/* 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;
|
||||
#endif
|
||||
|
||||
|
@ -208,7 +208,7 @@ class GHOST_SystemWayland : public GHOST_System {
|
||||
* Clear all references to this output.
|
||||
*
|
||||
* \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.
|
||||
*
|
||||
* \return true when any references were removed.
|
||||
|
@ -565,8 +565,8 @@ GHOST_TKey GHOST_SystemWin32::hardKey(RAWINPUT const &raw, bool *r_key_down)
|
||||
/**
|
||||
* \note this function can be extended to include other exotic cases as they arise.
|
||||
*
|
||||
* This function was added in response to bug T25715.
|
||||
* This is going to be a long list T42426.
|
||||
* This function was added in response to bug #25715.
|
||||
* This is going to be a long list #42426.
|
||||
*/
|
||||
GHOST_TKey GHOST_SystemWin32::processSpecialKey(short vKey, short scanCode) const
|
||||
{
|
||||
@ -1083,7 +1083,7 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
|
||||
* so the box needs to small enough not to let the cursor escape the window but large
|
||||
* 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
|
||||
* 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 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};
|
||||
@ -1209,7 +1209,7 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA
|
||||
const bool ctrl_pressed = has_state && state[VK_CONTROL] & 0x80;
|
||||
const bool 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!). */
|
||||
if (ctrl_pressed && !alt_pressed) {
|
||||
|
@ -46,7 +46,7 @@
|
||||
|
||||
#ifdef WITH_X11_XFIXES
|
||||
# include <X11/extensions/Xfixes.h>
|
||||
/* Workaround for XWayland grab glitch: T53004. */
|
||||
/* Workaround for XWayland grab glitch: #53004. */
|
||||
# define WITH_XWAYLAND_HACK
|
||||
#endif
|
||||
|
||||
@ -71,11 +71,11 @@
|
||||
# define USE_XINPUT_HOTPLUG
|
||||
#endif
|
||||
|
||||
/* see T34039 Fix Alt key glitch on Unity desktop */
|
||||
/* see #34039 Fix Alt key glitch on Unity desktop */
|
||||
#define USE_UNITY_WORKAROUND
|
||||
|
||||
/* 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
|
||||
|
||||
static uchar bit_is_on(const uchar *ptr, int bit)
|
||||
@ -928,7 +928,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
window->getClientBounds(bounds);
|
||||
|
||||
/* 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 size[2] = {bounds.getWidth(), bounds.getHeight()};
|
||||
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) {
|
||||
/* 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
|
||||
* 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
|
||||
* close events that will generate extra wrap on the same axis within those few
|
||||
* milliseconds. */
|
||||
@ -1028,7 +1028,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
/* XXX: Code below is kinda awfully convoluted... Issues are:
|
||||
* - In keyboards like Latin ones, numbers need a 'Shift' to be accessed but key_sym
|
||||
* 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.
|
||||
*
|
||||
* 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 ((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;
|
||||
if (XIGetClientPointer(m_display, None, &device_id) != False) {
|
||||
XIWarpPointer(m_display, device_id, None, None, 0, 0, 0, 0, relx, rely);
|
||||
|
@ -20,8 +20,8 @@
|
||||
|
||||
/* 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)
|
||||
* If this is supported we can add back XINPUT for warping (fixing T48901).
|
||||
* For now disable (see T50383). */
|
||||
* If this is supported we can add back XINPUT for warping (fixing #48901).
|
||||
* For now disable (see #50383). */
|
||||
// # define USE_X11_XINPUT_WARP
|
||||
#endif
|
||||
|
||||
|
@ -306,14 +306,23 @@ static void gwl_window_frame_update_from_pending(GWL_Window *win);
|
||||
#ifdef USE_EVENT_BACKGROUND_THREAD
|
||||
|
||||
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
|
||||
/** Draw an opaque region behind the window. */
|
||||
PENDING_OPAQUE_SET,
|
||||
# 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)
|
||||
{
|
||||
@ -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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
# ifdef GHOST_OPENGL_ALPHA
|
||||
@ -334,7 +343,7 @@ static void gwl_window_pending_actions_handle(GWL_Window *win)
|
||||
win->ghost_window->setOpaque();
|
||||
}
|
||||
# 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();
|
||||
}
|
||||
}
|
||||
@ -342,9 +351,10 @@ static void gwl_window_pending_actions_handle(GWL_Window *win)
|
||||
#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
|
||||
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
|
||||
std::lock_guard lock_frame_guard{win->frame_pending_mutex};
|
||||
#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;
|
||||
const bool is_main_thread = system->main_thread_id == std::this_thread::get_id();
|
||||
if (!is_main_thread) {
|
||||
gwl_window_pending_actions_tag(win, PENDING_FRAME_CONFIGURE);
|
||||
gwl_window_pending_actions_tag(win, PENDING_WINDOW_FRAME_CONFIGURE);
|
||||
}
|
||||
else
|
||||
# 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) {
|
||||
/* NOTE(@ideasman42): this only gets one redraw,
|
||||
* 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
|
||||
#endif
|
||||
@ -812,12 +822,12 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
|
||||
* when the `window_->scale` changed. */
|
||||
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.
|
||||
* For e.g. `org.blender.Blender` - however the `.desktop` file distributed with Blender is
|
||||
* simply called `blender.desktop`, so the it's important to follow that name.
|
||||
* Other distributions such as SNAP & FLATPAK may need to change this value T101779.
|
||||
* 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. */
|
||||
const char *xdg_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
|
||||
* (#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());
|
||||
|
||||
delete window_;
|
||||
@ -1373,7 +1383,7 @@ bool GHOST_WindowWayland::outputs_changed_update_scale()
|
||||
{
|
||||
#ifdef USE_EVENT_BACKGROUND_THREAD
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
@ -15,7 +15,7 @@
|
||||
#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
|
||||
*
|
||||
* Consume events from WAYLAND in a thread, this is needed because overflowing the event queue
|
||||
|
@ -93,7 +93,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
|
||||
}
|
||||
|
||||
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);
|
||||
m_hWnd = ::CreateWindowExW(extended_style, /* window extended style */
|
||||
@ -154,7 +154,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
|
||||
}
|
||||
|
||||
if (parentwindow) {
|
||||
/* Release any parent capture to allow immediate interaction (T90110). */
|
||||
/* Release any parent capture to allow immediate interaction (#90110). */
|
||||
::ReleaseCapture();
|
||||
parentwindow->lostMouseCapture();
|
||||
}
|
||||
@ -298,24 +298,52 @@ GHOST_WindowWin32::~GHOST_WindowWin32()
|
||||
m_directManipulationHelper = NULL;
|
||||
}
|
||||
|
||||
void GHOST_WindowWin32::adjustWindowRectForClosestMonitor(LPRECT win_rect,
|
||||
DWORD dwStyle,
|
||||
DWORD dwExStyle)
|
||||
void GHOST_WindowWin32::adjustWindowRectForDesktop(LPRECT win_rect, DWORD dwStyle, DWORD dwExStyle)
|
||||
{
|
||||
/* Get Details of the closest monitor. */
|
||||
HMONITOR hmonitor = MonitorFromRect(win_rect, MONITOR_DEFAULTTONEAREST);
|
||||
/* Windows can span multiple monitors, but must be usable. The desktop can have a larger
|
||||
* 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;
|
||||
monitor.cbSize = sizeof(MONITORINFOEX);
|
||||
monitor.dwFlags = 0;
|
||||
GetMonitorInfo(hmonitor, &monitor);
|
||||
|
||||
/* Constrain requested size and position to fit within this monitor. */
|
||||
LONG width = min(monitor.rcWork.right - monitor.rcWork.left, win_rect->right - win_rect->left);
|
||||
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);
|
||||
win_rect->right = win_rect->left + width;
|
||||
win_rect->top = min(max(monitor.rcWork.top, win_rect->top), monitor.rcWork.bottom - height);
|
||||
win_rect->bottom = win_rect->top + height;
|
||||
/* Note that with MonitorFromPoint using MONITOR_DEFAULTTONEAREST, it will return
|
||||
* the exact monitor if there is one at the location or the nearest monitor if not. */
|
||||
|
||||
/* Top-left. */
|
||||
pt.x = win_rect->left;
|
||||
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->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. */
|
||||
GHOST_WIN32_AdjustWindowRectExForDpi fpAdjustWindowRectExForDpi = nullptr;
|
||||
@ -334,9 +362,6 @@ void GHOST_WindowWin32::adjustWindowRectForClosestMonitor(LPRECT win_rect,
|
||||
else {
|
||||
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
|
||||
|
@ -87,12 +87,12 @@ class GHOST_WindowWin32 : public GHOST_Window {
|
||||
~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 dwStyle: The Window Style of the window whose required size is to be calculated.
|
||||
* \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.
|
||||
|
@ -418,7 +418,7 @@ void GHOST_WindowX11::refreshXInputDevices()
|
||||
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
|
||||
* 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;
|
||||
|
||||
@ -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) {
|
||||
setWindowCursorVisibility(true);
|
||||
}
|
||||
|
@ -281,6 +281,8 @@ inline T *MEM_new(const char *allocation_name, Args &&...args)
|
||||
*/
|
||||
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) {
|
||||
/* Support #ptr being null, because C++ `delete` supports that as well. */
|
||||
return;
|
||||
|
@ -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
|
||||
* 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) {
|
||||
std::cout << "bl_locale_set(" << locale << "): " << e.what() << " \n";
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ const char *osx_user_locale()
|
||||
[myNSLocale autorelease];
|
||||
|
||||
// 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];
|
||||
|
||||
const NSString *nsIdentifier = [myNSLocale languageCode];
|
||||
|
@ -193,7 +193,7 @@ static bool createGPUShader(OCIO_GPUShader &shader,
|
||||
info.fragment_source("gpu_shader_display_transform_frag.glsl");
|
||||
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.
|
||||
* (currently v2.1.1). */
|
||||
info.define("inf 1e32");
|
||||
|
@ -145,7 +145,7 @@ const UserDef U_default = {
|
||||
.ndof_flag = (NDOF_MODE_ORBIT | NDOF_LOCK_HORIZON | NDOF_SHOULD_PAN | NDOF_SHOULD_ZOOM |
|
||||
NDOF_SHOULD_ROTATE |
|
||||
/* 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_PANX_INVERT_AXIS | NDOF_PANY_INVERT_AXIS | NDOF_PANZ_INVERT_AXIS |
|
||||
NDOF_ZOOM_INVERT | NDOF_CAMERA_PAN_ZOOM),
|
||||
|
@ -370,6 +370,7 @@ const bTheme U_theme_default = {
|
||||
.clipping_border_3d = RGBA(0x3f3f3fff),
|
||||
.bundle_solid = RGBA(0xc8c8c8ff),
|
||||
.camera_path = RGBA(0x000000ff),
|
||||
.camera_passepartout = RGBA(0x000000),
|
||||
.gp_vertex_size = 3,
|
||||
.gp_vertex = RGBA(0x000000ff),
|
||||
.gp_vertex_select = RGBA(0xff8500ff),
|
||||
|
@ -286,7 +286,7 @@ class pySketchyChainingIterator(ChainingIterator):
|
||||
|
||||
if not 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:
|
||||
print('pySketchyChainingIterator: current edge not found')
|
||||
return None
|
||||
|
@ -113,7 +113,7 @@ def expand(line, cursor, namespace, *, private=True):
|
||||
if len(matches) == 1:
|
||||
scrollback = ''
|
||||
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])
|
||||
|
||||
# add white space to align with the cursor
|
||||
|
@ -30,7 +30,7 @@ def url_prefill_from_blender(*, addon_info=None):
|
||||
"**Blender Version**\n"
|
||||
)
|
||||
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.build_branch.decode('utf-8', 'replace'),
|
||||
bpy.app.build_commit_date.decode('utf-8', 'replace'),
|
||||
|
@ -32,7 +32,7 @@ class _BPyOpsSubModOp:
|
||||
# XXX You never quite know what you get from bpy.types,
|
||||
# with operators... Operator and OperatorProperties
|
||||
# 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 = _op_get_rna_type(idname)
|
||||
descr = op_class.description
|
||||
|
@ -259,15 +259,15 @@ def bake_action_iter(
|
||||
if is_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:
|
||||
# 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:
|
||||
atd.use_tweak_mode = False
|
||||
|
||||
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:
|
||||
atd.action_blend_type = 'REPLACE'
|
||||
|
||||
|
@ -111,7 +111,7 @@ def orientation_helper(axis_forward='Y', axis_up='Z'):
|
||||
"""
|
||||
def wrapper(cls):
|
||||
# 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__:
|
||||
setattr(cls, "__annotations__", {})
|
||||
|
||||
|
@ -564,7 +564,7 @@ class Mesh(bpy_types.ID):
|
||||
|
||||
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)
|
||||
edges_len = len(edges)
|
||||
faces_len = len(faces)
|
||||
|
@ -991,6 +991,7 @@ url_manual_mapping = (
|
||||
("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.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.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"),
|
||||
@ -2027,6 +2028,7 @@ url_manual_mapping = (
|
||||
("bpy.ops.graph.equalize_handles*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-equalize-handles"),
|
||||
("bpy.ops.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.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.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"),
|
||||
@ -3021,6 +3023,7 @@ url_manual_mapping = (
|
||||
("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.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.curve.offset*", "modeling/curves/properties/geometry.html#bpy-types-curve-offset"),
|
||||
("bpy.types.geometrynode*", "modeling/geometry_nodes/index.html#bpy-types-geometrynode"),
|
||||
|
@ -29,11 +29,11 @@
|
||||
icon_modifier="#84b8ffff"
|
||||
icon_shading="#ea7581ff"
|
||||
icon_folder="#e3c16eff"
|
||||
icon_border_intensity="0.85"
|
||||
icon_border_intensity="1"
|
||||
>
|
||||
<wcol_regular>
|
||||
<ThemeWidgetColors
|
||||
outline="#b8b8b8"
|
||||
outline="#4d4d4d"
|
||||
inner="#dbdbdbff"
|
||||
inner_sel="#668cccff"
|
||||
item="#191919ff"
|
||||
@ -48,7 +48,7 @@
|
||||
</wcol_regular>
|
||||
<wcol_tool>
|
||||
<ThemeWidgetColors
|
||||
outline="#b8b8b8"
|
||||
outline="#4d4d4d"
|
||||
inner="#dbdbdbff"
|
||||
inner_sel="#5680c2ff"
|
||||
item="#191919ff"
|
||||
@ -63,7 +63,7 @@
|
||||
</wcol_tool>
|
||||
<wcol_toolbar_item>
|
||||
<ThemeWidgetColors
|
||||
outline="#363636"
|
||||
outline="#4d4d4d"
|
||||
inner="#434343ff"
|
||||
inner_sel="#5680c2ff"
|
||||
item="#e6e6e6cc"
|
||||
@ -78,7 +78,7 @@
|
||||
</wcol_toolbar_item>
|
||||
<wcol_radio>
|
||||
<ThemeWidgetColors
|
||||
outline="#434343"
|
||||
outline="#4d4d4d"
|
||||
inner="#3b3b3bff"
|
||||
inner_sel="#5680c2e6"
|
||||
item="#ffffffff"
|
||||
@ -93,7 +93,7 @@
|
||||
</wcol_radio>
|
||||
<wcol_text>
|
||||
<ThemeWidgetColors
|
||||
outline="#666666"
|
||||
outline="#4d4d4d"
|
||||
inner="#282828ff"
|
||||
inner_sel="#333333ff"
|
||||
item="#5680c2ff"
|
||||
@ -108,7 +108,7 @@
|
||||
</wcol_text>
|
||||
<wcol_option>
|
||||
<ThemeWidgetColors
|
||||
outline="#373737"
|
||||
outline="#4d4d4d"
|
||||
inner="#3c3c3cff"
|
||||
inner_sel="#5680c2ff"
|
||||
item="#ffffffff"
|
||||
@ -123,8 +123,8 @@
|
||||
</wcol_option>
|
||||
<wcol_toggle>
|
||||
<ThemeWidgetColors
|
||||
outline="#999999"
|
||||
inner="#c0c0c0ff"
|
||||
outline="#4d4d4d"
|
||||
inner="#dbdbdbff"
|
||||
inner_sel="#5680c2ff"
|
||||
item="#191919ff"
|
||||
text="#000000"
|
||||
@ -138,7 +138,7 @@
|
||||
</wcol_toggle>
|
||||
<wcol_num>
|
||||
<ThemeWidgetColors
|
||||
outline="#b8b8b8"
|
||||
outline="#4d4d4d"
|
||||
inner="#d3d3d3ff"
|
||||
inner_sel="#5680c2ff"
|
||||
item="#80b1ffff"
|
||||
@ -153,7 +153,7 @@
|
||||
</wcol_num>
|
||||
<wcol_numslider>
|
||||
<ThemeWidgetColors
|
||||
outline="#b8b8b8"
|
||||
outline="#4d4d4d"
|
||||
inner="#999999ff"
|
||||
inner_sel="#999999ff"
|
||||
item="#e6e6e6ff"
|
||||
@ -168,8 +168,8 @@
|
||||
</wcol_numslider>
|
||||
<wcol_box>
|
||||
<ThemeWidgetColors
|
||||
outline="#959595"
|
||||
inner="#cccccc80"
|
||||
outline="#4d4d4d"
|
||||
inner="#80808080"
|
||||
inner_sel="#5680c2ff"
|
||||
item="#191919ff"
|
||||
text="#333333"
|
||||
@ -183,7 +183,7 @@
|
||||
</wcol_box>
|
||||
<wcol_menu>
|
||||
<ThemeWidgetColors
|
||||
outline="#3b3b3b"
|
||||
outline="#3d3d3d"
|
||||
inner="#3b3b3bff"
|
||||
inner_sel="#767676ff"
|
||||
item="#808080ff"
|
||||
@ -217,7 +217,7 @@
|
||||
inner="#c0c0c0ff"
|
||||
inner_sel="#cdcdcdff"
|
||||
item="#727272ff"
|
||||
text="#1a1a1a"
|
||||
text="#4d4d4d"
|
||||
text_sel="#1a1a1a"
|
||||
show_shaded="FALSE"
|
||||
shadetop="25"
|
||||
@ -304,11 +304,11 @@
|
||||
<wcol_list_item>
|
||||
<ThemeWidgetColors
|
||||
outline="#e6e6e6"
|
||||
inner="#00000000"
|
||||
inner_sel="#808080ff"
|
||||
inner="#1a1a1a00"
|
||||
inner_sel="#c0c0c0ff"
|
||||
item="#1a1a1aff"
|
||||
text="#1a1a1a"
|
||||
text_sel="#ffffff"
|
||||
text_sel="#000000"
|
||||
show_shaded="FALSE"
|
||||
shadetop="0"
|
||||
shadedown="0"
|
||||
@ -316,6 +316,21 @@
|
||||
>
|
||||
</ThemeWidgetColors>
|
||||
</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>
|
||||
<ThemeWidgetStateColors
|
||||
inner_anim="#73be4c"
|
||||
@ -334,8 +349,8 @@
|
||||
</wcol_state>
|
||||
<wcol_tab>
|
||||
<ThemeWidgetColors
|
||||
outline="#656565"
|
||||
inner="#818181ff"
|
||||
outline="#333333"
|
||||
inner="#808080cc"
|
||||
inner_sel="#b3b3b3ff"
|
||||
item="#28292dff"
|
||||
text="#1a1a1a"
|
||||
@ -414,6 +429,7 @@
|
||||
bone_locked_weight="#ff000080"
|
||||
bundle_solid="#c8c8c8"
|
||||
camera_path="#000000"
|
||||
camera_passepartout="#000000"
|
||||
skin_root="#b44d4d"
|
||||
view_overlay="#000000"
|
||||
transform="#ffffff"
|
||||
@ -452,9 +468,9 @@
|
||||
</gradients>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#b3b3b3ff"
|
||||
back="#b3b3b3cc"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
@ -519,9 +535,9 @@
|
||||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
@ -552,7 +568,7 @@
|
||||
header="#adadadff"
|
||||
header_text="#000000"
|
||||
header_text_hi="#ffffff"
|
||||
button="#999999e6"
|
||||
button="#b3b3b3ff"
|
||||
button_title="#1a1a1a"
|
||||
button_text="#000000"
|
||||
button_text_hi="#000000"
|
||||
@ -565,9 +581,9 @@
|
||||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
@ -623,9 +639,9 @@
|
||||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
@ -698,9 +714,9 @@
|
||||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
@ -783,9 +799,9 @@
|
||||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#b3b3b3ff"
|
||||
back="#b3b3b3cc"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
@ -843,14 +859,23 @@
|
||||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#b3b3b3ff"
|
||||
back="#b3b3b3cc"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
</ThemeSpaceGeneric>
|
||||
</space>
|
||||
<space_list>
|
||||
<ThemeSpaceListGeneric
|
||||
list="#181818"
|
||||
list_title="#ffffff"
|
||||
list_text="#ffffff"
|
||||
list_text_hi="#ffffff"
|
||||
>
|
||||
</ThemeSpaceListGeneric>
|
||||
</space_list>
|
||||
</ThemeSequenceEditor>
|
||||
</sequence_editor>
|
||||
<properties>
|
||||
@ -871,7 +896,7 @@
|
||||
button_title="#000000"
|
||||
button_text="#000000"
|
||||
button_text_hi="#000000"
|
||||
navigation_bar="#656565ff"
|
||||
navigation_bar="#1d1d1dff"
|
||||
execution_buts="#00000000"
|
||||
tab_active="#6697e6"
|
||||
tab_inactive="#535353"
|
||||
@ -880,9 +905,9 @@
|
||||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#b3b3b300"
|
||||
back="#a3a3a3cc"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
@ -927,9 +952,9 @@
|
||||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
@ -939,44 +964,44 @@
|
||||
</text_editor>
|
||||
<node_editor>
|
||||
<ThemeNodeEditor
|
||||
grid="#1B1B1B"
|
||||
node_selected="#f15800"
|
||||
node_active="#f15800"
|
||||
wire="#191919"
|
||||
wire_inner="#999999"
|
||||
wire_select="#ffa733"
|
||||
selected_text="#7f7070"
|
||||
node_backdrop="#e6e6e6ff"
|
||||
converter_node="#66c4ff"
|
||||
color_node="#ffcb4d"
|
||||
group_node="#59b36ab9"
|
||||
group_socket_node="#dfc300"
|
||||
frame_node="#9b9b9b60"
|
||||
matte_node="#977474"
|
||||
distor_node="#749797"
|
||||
grid="#282828"
|
||||
node_selected="#ed5700"
|
||||
node_active="#ffffff"
|
||||
wire="#1a1a1aff"
|
||||
wire_inner="#8d8d8d"
|
||||
wire_select="#ffffffb3"
|
||||
selected_text="#7f7f7f"
|
||||
node_backdrop="#666666ff"
|
||||
converter_node="#12adff"
|
||||
color_node="#cccc00"
|
||||
group_node="#3b660a"
|
||||
group_socket_node="#000000"
|
||||
frame_node="#0f0f0fcc"
|
||||
matte_node="#973c3c"
|
||||
distor_node="#4c9797"
|
||||
noodle_curving="4"
|
||||
grid_levels="3"
|
||||
dash_alpha="0.5"
|
||||
input_node="#cb3d4a"
|
||||
output_node="#cb3d4a"
|
||||
filter_node="#6c696f"
|
||||
vector_node="#9999ff"
|
||||
texture_node="#ffc399"
|
||||
shader_node="#ea7581"
|
||||
script_node="#6c696f"
|
||||
input_node="#ff3371"
|
||||
output_node="#4d0017"
|
||||
filter_node="#551a80"
|
||||
vector_node="#4d4dff"
|
||||
texture_node="#e66800"
|
||||
shader_node="#24b524"
|
||||
script_node="#084d4d"
|
||||
pattern_node="#6c696f"
|
||||
layout_node="#6c696f"
|
||||
geometry_node="#00d7a4"
|
||||
attribute_node="#3f5980"
|
||||
geometry_node="#00d6a3"
|
||||
attribute_node="#001566"
|
||||
>
|
||||
<space>
|
||||
<ThemeSpaceGeneric
|
||||
back="#353535"
|
||||
title="#000000"
|
||||
text="#000000"
|
||||
back="#1d1d1d"
|
||||
title="#eeeeee"
|
||||
text="#e6e6e6"
|
||||
text_hi="#ffffff"
|
||||
header="#b3b3b3ff"
|
||||
header_text="#000000"
|
||||
header_text="#eeeeee"
|
||||
header_text_hi="#ffffff"
|
||||
button="#99999900"
|
||||
button_title="#1a1a1a"
|
||||
@ -991,9 +1016,9 @@
|
||||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#b3b3b3ff"
|
||||
back="#b3b3b3cc"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
@ -1013,8 +1038,8 @@
|
||||
<outliner>
|
||||
<ThemeOutliner
|
||||
match="#337f33"
|
||||
selected_highlight="#7a8e99"
|
||||
active="#92aab7"
|
||||
selected_highlight="#7a8499"
|
||||
active="#929eb7"
|
||||
selected_object="#ffddb3"
|
||||
active_object="#ffffff"
|
||||
edited_object="#0080624d"
|
||||
@ -1042,9 +1067,9 @@
|
||||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
@ -1091,9 +1116,9 @@
|
||||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
@ -1125,9 +1150,9 @@
|
||||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#b3b3b300"
|
||||
back="#a3a3a3cc"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
@ -1137,26 +1162,26 @@
|
||||
</preferences>
|
||||
<console>
|
||||
<ThemeConsole
|
||||
line_output="#6080ff"
|
||||
line_input="#ffffff"
|
||||
line_info="#00aa00"
|
||||
line_error="#dc6060"
|
||||
cursor="#dc6060"
|
||||
line_output="#71a8ff"
|
||||
line_input="#f2f2f2"
|
||||
line_info="#95d600"
|
||||
line_error="#ff4d84"
|
||||
cursor="#ff0000"
|
||||
select="#ffffff30"
|
||||
>
|
||||
<space>
|
||||
<ThemeSpaceGeneric
|
||||
back="#000000"
|
||||
title="#000000"
|
||||
text="#000000"
|
||||
back="#1d1d1d"
|
||||
title="#eeeeee"
|
||||
text="#e6e6e6"
|
||||
text_hi="#ffffff"
|
||||
header="#b3b3b3ff"
|
||||
header_text="#000000"
|
||||
header_text_hi="#ffffff"
|
||||
button="#7272727f"
|
||||
button_title="#000000"
|
||||
button_text="#000000"
|
||||
button_text_hi="#000000"
|
||||
button="#30303000"
|
||||
button_title="#ffffff"
|
||||
button_text="#cccccc"
|
||||
button_text_hi="#ffffff"
|
||||
navigation_bar="#00000000"
|
||||
execution_buts="#00000000"
|
||||
tab_active="#6697e6"
|
||||
@ -1166,9 +1191,9 @@
|
||||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
@ -1231,9 +1256,9 @@
|
||||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
@ -1274,9 +1299,9 @@
|
||||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
@ -1292,7 +1317,7 @@
|
||||
title="#ffffff"
|
||||
text="#ffffff"
|
||||
text_hi="#ffffff"
|
||||
header="#adadadff"
|
||||
header="#999999ff"
|
||||
header_text="#1a1a1a"
|
||||
header_text_hi="#ffffff"
|
||||
button="#2f303500"
|
||||
@ -1308,9 +1333,9 @@
|
||||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
@ -1331,7 +1356,7 @@
|
||||
header="#adadadff"
|
||||
header_text="#000000"
|
||||
header_text_hi="#ffffff"
|
||||
button="#999999e6"
|
||||
button="#b3b3b3ff"
|
||||
button_title="#1a1a1a"
|
||||
button_text="#000000"
|
||||
button_text_hi="#000000"
|
||||
@ -1344,9 +1369,9 @@
|
||||
>
|
||||
<panelcolors>
|
||||
<ThemePanelColors
|
||||
header="#42424200"
|
||||
back="#00000028"
|
||||
sub_back="#00000024"
|
||||
header="#ccccccff"
|
||||
back="#ccccccff"
|
||||
sub_back="#0000000f"
|
||||
>
|
||||
</ThemePanelColors>
|
||||
</panelcolors>
|
||||
@ -1585,8 +1610,8 @@
|
||||
shadow="3"
|
||||
shadow_offset_x="0"
|
||||
shadow_offset_y="-1"
|
||||
shadow_alpha="0.3"
|
||||
shadow_value="0.7"
|
||||
shadow_alpha="1"
|
||||
shadow_value="0.8"
|
||||
>
|
||||
</ThemeFontStyle>
|
||||
</panel_title>
|
||||
@ -1596,8 +1621,8 @@
|
||||
shadow="3"
|
||||
shadow_offset_x="0"
|
||||
shadow_offset_y="-1"
|
||||
shadow_alpha="0.3"
|
||||
shadow_value="0.7"
|
||||
shadow_alpha="0"
|
||||
shadow_value="0.8"
|
||||
>
|
||||
</ThemeFontStyle>
|
||||
</widget_label>
|
||||
@ -1607,8 +1632,8 @@
|
||||
shadow="1"
|
||||
shadow_offset_x="0"
|
||||
shadow_offset_y="-1"
|
||||
shadow_alpha="0.3"
|
||||
shadow_value="0.7"
|
||||
shadow_alpha="0"
|
||||
shadow_value="0.8"
|
||||
>
|
||||
</ThemeFontStyle>
|
||||
</widget>
|
||||
|
@ -86,7 +86,7 @@ class Prefs(bpy.types.KeyConfigPreferences):
|
||||
update=update_fn,
|
||||
)
|
||||
|
||||
# Experimental: only show with developer extras, see: T96544.
|
||||
# Experimental: only show with developer extras, see: #96544.
|
||||
use_tweak_select_passthrough: BoolProperty(
|
||||
name="Tweak Select: Mouse Select & Move",
|
||||
description=(
|
||||
@ -96,7 +96,7 @@ class Prefs(bpy.types.KeyConfigPreferences):
|
||||
default=False,
|
||||
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(
|
||||
name="Tweak Tool: Left Mouse Select & Move",
|
||||
description=(
|
||||
|
@ -37,7 +37,7 @@ class Params:
|
||||
# instead be bound to a binding that doesn't de-select all, this way:
|
||||
# - Click-drag moves the current selection.
|
||||
# - Click selects only the item at the cursor position.
|
||||
# See: T97032.
|
||||
# See: #97032.
|
||||
"use_tweak_select_passthrough",
|
||||
"use_tweak_tool_lmb_interaction",
|
||||
"use_mouse_emulate_3_button",
|
||||
@ -465,7 +465,7 @@ def _template_items_tool_select(
|
||||
fallback=False,
|
||||
):
|
||||
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.
|
||||
# For LMB-select this means an LMB -drag will not first de-select all (similar to node/graph editor).
|
||||
select_passthrough = False
|
||||
@ -498,7 +498,7 @@ def _template_items_tool_select(
|
||||
{"properties": [("toggle", True), *operator_props]}),
|
||||
|
||||
# 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 (
|
||||
("transform.translate", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG'},
|
||||
{"properties": [("release_confirm", True)]}),
|
||||
@ -4730,7 +4730,7 @@ def _template_paint_radial_control(paint, rotation=False, secondary_rotation=Fal
|
||||
|
||||
def _template_view3d_select(*, type, value, legacy, select_passthrough, exclude_mod=None):
|
||||
# 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 = ()
|
||||
if select_passthrough:
|
||||
@ -5629,6 +5629,10 @@ def km_curves(params):
|
||||
("curves.disable_selection", {"type": 'TWO', "value": 'PRESS', "alt": True}, None),
|
||||
*_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
|
||||
@ -5683,7 +5687,7 @@ def km_object_non_modal(params):
|
||||
])
|
||||
else:
|
||||
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),
|
||||
])
|
||||
|
||||
@ -6345,9 +6349,8 @@ def km_node_link_modal_map(_params):
|
||||
|
||||
return keymap
|
||||
|
||||
|
||||
# Fallback for gizmos that don't have custom a custom key-map.
|
||||
|
||||
|
||||
def km_generic_gizmo(_params):
|
||||
keymap = (
|
||||
"Generic Gizmo",
|
||||
|
@ -6,8 +6,8 @@ from bpy.types import Operator
|
||||
from bpy.app.translations import pgettext_data as data_
|
||||
|
||||
|
||||
def geometry_node_group_empty_new():
|
||||
group = bpy.data.node_groups.new(data_("Geometry Nodes"), 'GeometryNodeTree')
|
||||
def build_default_empty_geometry_node_group(name):
|
||||
group = bpy.data.node_groups.new(name, 'GeometryNodeTree')
|
||||
group.inputs.new('NodeSocketGeometry', data_("Geometry"))
|
||||
group.outputs.new('NodeSocketGeometry', data_("Geometry"))
|
||||
input_node = group.nodes.new('NodeGroupInput')
|
||||
@ -20,8 +20,12 @@ def geometry_node_group_empty_new():
|
||||
input_node.location.x = -200 - input_node.width
|
||||
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
|
||||
|
||||
|
||||
@ -35,6 +39,158 @@ def geometry_modifier_poll(context):
|
||||
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):
|
||||
"""Create a new modifier with a new geometry node group"""
|
||||
|
||||
@ -48,7 +204,6 @@ class NewGeometryNodesModifier(Operator):
|
||||
|
||||
def execute(self, context):
|
||||
modifier = context.object.modifiers.new(data_("GeometryNodes"), "NODES")
|
||||
|
||||
if not modifier:
|
||||
return {'CANCELLED'}
|
||||
|
||||
@ -70,11 +225,7 @@ class NewGeometryNodeTreeAssign(Operator):
|
||||
return geometry_modifier_poll(context)
|
||||
|
||||
def execute(self, context):
|
||||
if context.area.type == 'PROPERTIES':
|
||||
modifier = context.modifier
|
||||
else:
|
||||
modifier = context.object.modifiers.active
|
||||
|
||||
modifier = get_context_modifier(context)
|
||||
if not modifier:
|
||||
return {'CANCELLED'}
|
||||
|
||||
@ -87,4 +238,5 @@ class NewGeometryNodeTreeAssign(Operator):
|
||||
classes = (
|
||||
NewGeometryNodesModifier,
|
||||
NewGeometryNodeTreeAssign,
|
||||
MoveModifierToNodes,
|
||||
)
|
||||
|
@ -790,7 +790,7 @@ class TransformsToDeltasAnim(Operator):
|
||||
continue
|
||||
|
||||
# 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 = {}
|
||||
for fcu in adt.action.fcurves:
|
||||
# get "delta" path - i.e. the final paths which may clash
|
||||
|
@ -36,67 +36,136 @@ class ObjectModeOperator:
|
||||
|
||||
|
||||
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_label = "Quick Fur"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
density: EnumProperty(
|
||||
name="Fur Density",
|
||||
name="Density",
|
||||
items=(
|
||||
('LIGHT', "Light", ""),
|
||||
('LOW', "Low", ""),
|
||||
('MEDIUM', "Medium", ""),
|
||||
('HEAVY', "Heavy", ""),
|
||||
('HIGH', "High", ""),
|
||||
),
|
||||
default='MEDIUM',
|
||||
)
|
||||
view_percentage: IntProperty(
|
||||
name="View %",
|
||||
min=1, max=100,
|
||||
soft_min=1, soft_max=100,
|
||||
default=10,
|
||||
)
|
||||
length: FloatProperty(
|
||||
name="Length",
|
||||
min=0.001, max=100,
|
||||
soft_min=0.01, soft_max=10,
|
||||
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):
|
||||
fake_context = context.copy()
|
||||
mesh_objects = [obj for obj in context.selected_objects
|
||||
if obj.type == 'MESH']
|
||||
|
||||
import os
|
||||
mesh_objects = [obj for obj in context.selected_objects if obj.type == 'MESH']
|
||||
if not mesh_objects:
|
||||
self.report({'ERROR'}, "Select at least one mesh object")
|
||||
return {'CANCELLED'}
|
||||
|
||||
mat = bpy.data.materials.new("Fur Material")
|
||||
|
||||
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
|
||||
if self.density == 'LOW':
|
||||
count = 1000
|
||||
elif self.density == 'MEDIUM':
|
||||
psys.settings.count = 1000
|
||||
elif self.density == 'HEAVY':
|
||||
psys.settings.count = 10000
|
||||
count = 10000
|
||||
elif self.density == 'HIGH':
|
||||
count = 100000
|
||||
|
||||
psys.settings.child_nbr = self.view_percentage
|
||||
psys.settings.hair_length = self.length
|
||||
psys.settings.use_strand_primitive = True
|
||||
psys.settings.use_hair_bspline = True
|
||||
psys.settings.child_type = 'INTERPOLATED'
|
||||
psys.settings.tip_radius = 0.25
|
||||
node_groups_to_append = {"Generate Hair Curves", "Set Hair Curve Profile", "Interpolate Hair Curves"}
|
||||
if self.use_noise:
|
||||
node_groups_to_append.add("Hair Curves Noise")
|
||||
if self.use_frizz:
|
||||
node_groups_to_append.add("Frizz Hair Curves")
|
||||
assets_directory = os.path.join(bpy.utils.system_resource('DATAFILES'),
|
||||
"assets",
|
||||
"geometry_nodes",
|
||||
"procedural_hair_node_assets.blend",
|
||||
"NodeTree")
|
||||
for name in node_groups_to_append:
|
||||
bpy.ops.wm.append(directory=assets_directory,
|
||||
filename=name,
|
||||
use_recursive=True,
|
||||
clear_asset_data=True,
|
||||
do_reuse_local_id=True)
|
||||
generate_group = bpy.data.node_groups["Generate Hair Curves"]
|
||||
interpolate_group = bpy.data.node_groups["Interpolate Hair Curves"]
|
||||
radius_group = bpy.data.node_groups["Set Hair Curve Profile"]
|
||||
noise_group = bpy.data.node_groups["Hair Curves Noise"] if self.use_noise else None
|
||||
frizz_group = bpy.data.node_groups["Frizz Hair Curves"] if self.use_frizz else None
|
||||
|
||||
obj.data.materials.append(mat)
|
||||
psys.settings.material = len(obj.data.materials)
|
||||
material = bpy.data.materials.new("Fur Material")
|
||||
|
||||
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'}
|
||||
|
||||
|
@ -700,7 +700,7 @@ class PREFERENCES_OT_addon_install(Operator):
|
||||
addons_new.discard("modules")
|
||||
|
||||
# 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:
|
||||
addon_utils.disable(new_addon, default_set=True)
|
||||
|
||||
|
@ -581,7 +581,7 @@ class LightMapPack(Operator):
|
||||
# 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
|
||||
# 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'}
|
||||
|
||||
PREF_CONTEXT: bpy.props.EnumProperty(
|
||||
|
@ -90,7 +90,7 @@ def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean,
|
||||
tone_range = max_tone - min_tone
|
||||
|
||||
if tone_range < 0.0001:
|
||||
# weak, don't cancel, see T43345
|
||||
# weak, don't cancel, see #43345
|
||||
tone_range = 0.0
|
||||
else:
|
||||
tone_range = 1.0 / tone_range
|
||||
|
@ -42,7 +42,7 @@ class VIEW3D_OT_edit_mesh_extrude_individual_move(Operator):
|
||||
bpy.ops.mesh.extrude_vertices_move('INVOKE_REGION_WIN')
|
||||
|
||||
# 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'}
|
||||
|
||||
def invoke(self, context, _event):
|
||||
@ -104,7 +104,7 @@ class VIEW3D_OT_edit_mesh_extrude_move(Operator):
|
||||
'INVOKE_REGION_WIN',
|
||||
TRANSFORM_OT_translate={
|
||||
# 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',
|
||||
# Not a popular choice, too restrictive for retopo.
|
||||
# "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')
|
||||
|
||||
# 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'}
|
||||
|
||||
def execute(self, context):
|
||||
|
@ -1249,7 +1249,31 @@ class WM_OT_doc_view_manual(Operator):
|
||||
# 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.
|
||||
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:
|
||||
|
||||
# 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 verbose:
|
||||
print(" match found: '%s' --> '%s'" % (pattern, url_suffix))
|
||||
@ -1725,7 +1749,7 @@ class WM_OT_properties_edit(Operator):
|
||||
for nt in adt.nla_tracks:
|
||||
_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 area in win.screen.areas:
|
||||
area.tag_redraw()
|
||||
|
@ -604,7 +604,7 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel):
|
||||
colliding_names = []
|
||||
for collection in (
|
||||
# Built-in names.
|
||||
{"shade_smooth": None, "normal": None, "crease": None},
|
||||
{"shade_smooth": None, "crease": None},
|
||||
mesh.attributes,
|
||||
None if ob is None else ob.vertex_groups,
|
||||
):
|
||||
|
@ -1141,6 +1141,11 @@ def brush_texture_settings(layout, brush, sculpt):
|
||||
# texture_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):
|
||||
mask_tex_slot = brush.mask_texture_slot
|
||||
|
@ -91,7 +91,7 @@ class TEXTURE_PT_preview(TextureButtonsPanel, Panel):
|
||||
else:
|
||||
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)
|
||||
if isinstance(idblock, Brush):
|
||||
layout.prop(tex, "use_preview_alpha")
|
||||
|
@ -22,7 +22,7 @@ class FILEBROWSER_HT_header(Header):
|
||||
|
||||
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.separator_spacer()
|
||||
|
@ -62,7 +62,7 @@ class NODE_HT_header(Header):
|
||||
|
||||
types_that_support_material = {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META',
|
||||
'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
|
||||
has_material_slots = not snode.pin and ob_type in types_that_support_material
|
||||
|
||||
|
@ -407,7 +407,7 @@ class SEQUENCER_MT_view(Menu):
|
||||
if st.view_type == 'PREVIEW':
|
||||
# Specifying the REGION_PREVIEW context is needed in preview-only
|
||||
# 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.prop(st, "show_region_ui")
|
||||
layout.prop(st, "show_region_tool_header")
|
||||
@ -429,7 +429,7 @@ class SEQUENCER_MT_view(Menu):
|
||||
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
if st.view_type == 'PREVIEW':
|
||||
# See above (T32595)
|
||||
# See above (#32595)
|
||||
layout.operator_context = 'INVOKE_REGION_PREVIEW'
|
||||
layout.operator("sequencer.view_selected", text="Frame Selected")
|
||||
|
||||
@ -931,8 +931,14 @@ class SEQUENCER_MT_strip(Menu):
|
||||
|
||||
if has_sequencer:
|
||||
|
||||
layout.operator("sequencer.split", text="Split").type = 'SOFT'
|
||||
layout.operator("sequencer.split", text="Hold Split").type = 'HARD'
|
||||
props = layout.operator("sequencer.split", text="Split")
|
||||
props.type = 'SOFT'
|
||||
props.side = 'RIGHT'
|
||||
|
||||
props = layout.operator("sequencer.split", text="Hold Split")
|
||||
props.type = 'HARD'
|
||||
props.side = 'RIGHT'
|
||||
|
||||
layout.separator()
|
||||
|
||||
if has_sequencer:
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -326,7 +326,7 @@ class TOPBAR_MT_file_new(Menu):
|
||||
# Expand template paths.
|
||||
|
||||
# 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()
|
||||
for path in template_paths:
|
||||
for d in os.listdir(path):
|
||||
|
@ -1424,34 +1424,40 @@ class USERPREF_PT_file_paths_asset_libraries(FilePathsPanel, Panel):
|
||||
layout.use_property_decorate = False
|
||||
|
||||
paths = context.preferences.filepaths
|
||||
active_library_index = paths.active_asset_library
|
||||
|
||||
box = layout.box()
|
||||
split = box.split(factor=0.35)
|
||||
name_col = split.column()
|
||||
path_col = split.column()
|
||||
row = layout.row()
|
||||
|
||||
row = name_col.row(align=True) # Padding
|
||||
row.separator()
|
||||
row.label(text="Name")
|
||||
row.template_list(
|
||||
"USERPREF_UL_asset_libraries", "user_asset_libraries",
|
||||
paths, "asset_libraries",
|
||||
paths, "active_asset_library"
|
||||
)
|
||||
|
||||
row = path_col.row(align=True) # Padding
|
||||
row.separator()
|
||||
row.label(text="Path")
|
||||
col = row.column(align=True)
|
||||
col.operator("preferences.asset_library_add", text="", icon='ADD')
|
||||
props = col.operator("preferences.asset_library_remove", text="", icon='REMOVE')
|
||||
props.index = active_library_index
|
||||
|
||||
for i, library in enumerate(paths.asset_libraries):
|
||||
row = name_col.row()
|
||||
row.alert = not library.name
|
||||
row.prop(library, "name", text="")
|
||||
if active_library_index < 0:
|
||||
return
|
||||
|
||||
row = path_col.row()
|
||||
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
|
||||
layout.separator()
|
||||
|
||||
row = box.row()
|
||||
row.alignment = 'RIGHT'
|
||||
row.operator("preferences.asset_library_add", text="", icon='ADD', emboss=False)
|
||||
active_library = paths.asset_libraries[active_library_index]
|
||||
layout.prop(active_library, "path")
|
||||
layout.prop(active_library, "import_method", text="Import Method")
|
||||
|
||||
|
||||
class USERPREF_UL_asset_libraries(bpy.types.UIList):
|
||||
def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):
|
||||
asset_library = item
|
||||
|
||||
if self.layout_type in {'DEFAULT', 'COMPACT'}:
|
||||
layout.prop(asset_library, "name", text="", emboss=False)
|
||||
elif self.layout_type == 'GRID':
|
||||
layout.alignment = 'CENTER'
|
||||
layout.prop(asset_library, "name", text="", emboss=False)
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@ -2319,19 +2325,13 @@ class USERPREF_PT_experimental_new_features(ExperimentalPanel, Panel):
|
||||
bl_label = "New Features"
|
||||
|
||||
def draw(self, context):
|
||||
self._draw_items(context,
|
||||
(({"property": "use_sculpt_tools_tilt"},
|
||||
("blender/blender/issues/82877",
|
||||
"#82877")),
|
||||
self._draw_items(
|
||||
context, (
|
||||
({"property": "use_sculpt_tools_tilt"}, ("blender/blender/issues/82877", "#82877")),
|
||||
({"property": "use_extended_asset_browser"},
|
||||
("blender/blender/projects/10",
|
||||
"Pipeline, Assets & IO Project Page")),
|
||||
({"property": "use_override_templates"},
|
||||
("blender/blender/issues/73318",
|
||||
"Milestone 4")),
|
||||
({"property": "use_new_volume_nodes"},
|
||||
("blender/blender/issues/103248",
|
||||
"#103248")),
|
||||
("blender/blender/projects/10", "Pipeline, Assets & IO Project Page")),
|
||||
({"property": "use_override_templates"}, ("blender/blender/issues/73318", "Milestone 4")),
|
||||
({"property": "use_new_volume_nodes"}, ("blender/blender/issues/103248", "#103248")),
|
||||
),
|
||||
)
|
||||
|
||||
@ -2493,6 +2493,9 @@ classes = (
|
||||
# USERPREF_PT_experimental_tweaks,
|
||||
USERPREF_PT_experimental_debugging,
|
||||
|
||||
# UI lists
|
||||
USERPREF_UL_asset_libraries,
|
||||
|
||||
# Add dynamically generated editor theme panels last,
|
||||
# so they show up last in the theme section.
|
||||
*ThemeGenericClassGenerator.generate_panel_classes_from_theme_areas(),
|
||||
|
@ -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_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.
|
||||
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':
|
||||
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':
|
||||
layout.prop(brush, "falloff_shape", expand=True)
|
||||
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'})
|
||||
|
||||
# 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:
|
||||
draw_depressed = overlay.show_xray_bone
|
||||
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")
|
||||
|
||||
|
||||
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):
|
||||
bl_label = "Select"
|
||||
|
||||
@ -2050,10 +2063,17 @@ class VIEW3D_MT_select_edit_curves(Menu):
|
||||
layout.operator("curves.select_all", text="All").action = 'SELECT'
|
||||
layout.operator("curves.select_all", text="None").action = 'DESELECT'
|
||||
layout.operator("curves.select_all", text="Invert").action = 'INVERT'
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("curves.select_random", text="Random")
|
||||
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):
|
||||
bl_label = "Select"
|
||||
@ -2114,6 +2134,7 @@ class VIEW3D_MT_curve_add(Menu):
|
||||
layout.separator()
|
||||
|
||||
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
|
||||
if experimental.use_new_curves_tools:
|
||||
@ -2268,7 +2289,7 @@ class VIEW3D_MT_add(Menu):
|
||||
# NOTE: don't use 'EXEC_SCREEN' or operators won't get the `v3d` context.
|
||||
|
||||
# NOTE: 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_menu_enum("object.mesh_add", "type", text="Mesh", icon='OUTLINER_OB_MESH')
|
||||
@ -3867,6 +3888,7 @@ class VIEW3D_MT_edit_mesh(Menu):
|
||||
layout.menu("VIEW3D_MT_edit_mesh_normals")
|
||||
layout.menu("VIEW3D_MT_edit_mesh_shading")
|
||||
layout.menu("VIEW3D_MT_edit_mesh_weights")
|
||||
layout.operator("mesh.attribute_set")
|
||||
layout.operator_menu_enum("mesh.sort_elements", "type", text="Sort Elements...")
|
||||
|
||||
layout.separator()
|
||||
@ -5308,6 +5330,7 @@ class VIEW3D_MT_edit_curves(Menu):
|
||||
|
||||
layout.menu("VIEW3D_MT_transform")
|
||||
layout.separator()
|
||||
layout.operator("curves.delete")
|
||||
|
||||
|
||||
class VIEW3D_MT_object_mode_pie(Menu):
|
||||
@ -5376,7 +5399,7 @@ class VIEW3D_MT_shading_ex_pie(Menu):
|
||||
pie.prop_enum(view.shading, "type", value='WIREFRAME')
|
||||
pie.prop_enum(view.shading, "type", value='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:
|
||||
pie.prop(view.overlay, "show_xray_bone", icon='XRAY')
|
||||
else:
|
||||
@ -6718,15 +6741,15 @@ class VIEW3D_PT_overlay_sculpt(Panel):
|
||||
overlay = view.overlay
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(overlay, "sculpt_show_mask", text="")
|
||||
row.prop(overlay, "show_sculpt_mask", text="")
|
||||
sub = row.row()
|
||||
sub.active = overlay.sculpt_show_mask
|
||||
sub.active = overlay.show_sculpt_mask
|
||||
sub.prop(overlay, "sculpt_mode_mask_opacity", text="Mask")
|
||||
|
||||
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.active = overlay.sculpt_show_face_sets
|
||||
sub.active = overlay.show_sculpt_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.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):
|
||||
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")
|
||||
|
||||
|
||||
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):
|
||||
# Only for popover, these are dummy values.
|
||||
bl_space_type = 'VIEW_3D'
|
||||
@ -8011,6 +8063,7 @@ classes = (
|
||||
VIEW3D_MT_select_gpencil,
|
||||
VIEW3D_MT_select_paint_mask,
|
||||
VIEW3D_MT_select_paint_mask_vertex,
|
||||
VIEW3D_MT_edit_curves_select_more_less,
|
||||
VIEW3D_MT_select_edit_curves,
|
||||
VIEW3D_MT_select_sculpt_curves,
|
||||
VIEW3D_MT_mesh_add,
|
||||
@ -8211,6 +8264,7 @@ classes = (
|
||||
TOPBAR_PT_gpencil_vertexcolor,
|
||||
TOPBAR_PT_annotation_layers,
|
||||
VIEW3D_PT_curves_sculpt_add_shape,
|
||||
VIEW3D_PT_curves_sculpt_parameter_falloff,
|
||||
VIEW3D_PT_curves_sculpt_grow_shrink_scaling,
|
||||
VIEW3D_PT_viewport_debug,
|
||||
)
|
||||
|
@ -639,7 +639,7 @@ class BUILTIN_KSI_DeltaScale(KeyingSetInfo):
|
||||
|
||||
# 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.
|
||||
# See also T51867.
|
||||
# See also #51867.
|
||||
classes = (
|
||||
BUILTIN_KSI_Available,
|
||||
BUILTIN_KSI_Location,
|
||||
|
@ -58,6 +58,11 @@ class AssetLibrary {
|
||||
|
||||
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_{};
|
||||
|
||||
public:
|
||||
@ -68,6 +73,7 @@ class AssetLibrary {
|
||||
std::unique_ptr<AssetCatalogService> catalog_service;
|
||||
|
||||
friend class AssetLibraryService;
|
||||
friend class AssetRepresentation;
|
||||
|
||||
public:
|
||||
/**
|
||||
|
@ -22,6 +22,8 @@ const char *AS_asset_representation_name_get(const AssetRepresentation *asset)
|
||||
AssetMetaData *AS_asset_representation_metadata_get(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
|
||||
}
|
||||
|
@ -12,10 +12,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "BLI_string_ref.hh"
|
||||
|
||||
#include "DNA_asset_types.h"
|
||||
|
||||
#include "AS_asset_identifier.hh"
|
||||
|
||||
struct AssetMetaData;
|
||||
@ -23,11 +26,15 @@ struct ID;
|
||||
|
||||
namespace blender::asset_system {
|
||||
|
||||
class AssetLibrary;
|
||||
|
||||
class AssetRepresentation {
|
||||
AssetIdentifier identifier_;
|
||||
/** Indicate if this is a local or external asset, and as such, which of the union members below
|
||||
* should be used. */
|
||||
const bool is_local_id_ = false;
|
||||
/** Asset library that owns this asset representation. */
|
||||
const AssetLibrary *owner_asset_library_;
|
||||
|
||||
struct ExternalAsset {
|
||||
std::string name;
|
||||
@ -44,10 +51,13 @@ class AssetRepresentation {
|
||||
/** Constructs an asset representation for an external ID. The asset will not be editable. */
|
||||
AssetRepresentation(AssetIdentifier &&identifier,
|
||||
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
|
||||
* local and fully editable. */
|
||||
AssetRepresentation(AssetIdentifier &&identifier, ID &id);
|
||||
AssetRepresentation(AssetIdentifier &&identifier,
|
||||
ID &id,
|
||||
const AssetLibrary &owner_asset_library);
|
||||
AssetRepresentation(AssetRepresentation &&other);
|
||||
/* Non-copyable type. */
|
||||
AssetRepresentation(const AssetRepresentation &other) = delete;
|
||||
@ -63,8 +73,18 @@ class AssetRepresentation {
|
||||
|
||||
StringRefNull get_name() 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. */
|
||||
bool is_local_id() const;
|
||||
const AssetLibrary &owner_asset_library() const;
|
||||
};
|
||||
|
||||
} // namespace blender::asset_system
|
||||
@ -73,3 +93,6 @@ class AssetRepresentation {
|
||||
struct AssetRepresentation;
|
||||
|
||||
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);
|
||||
|
15
source/blender/asset_system/AS_essentials_library.hh
Normal file
15
source/blender/asset_system/AS_essentials_library.hh
Normal 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();
|
||||
|
||||
}
|
@ -17,6 +17,7 @@ set(SRC
|
||||
intern/asset_catalog.cc
|
||||
intern/asset_catalog_path.cc
|
||||
intern/asset_catalog_tree.cc
|
||||
intern/asset_essentials_library.cc
|
||||
intern/asset_identifier.cc
|
||||
intern/asset_library.cc
|
||||
intern/asset_library_service.cc
|
||||
@ -30,6 +31,7 @@ set(SRC
|
||||
AS_asset_identifier.hh
|
||||
AS_asset_library.hh
|
||||
AS_asset_representation.hh
|
||||
AS_essentials_library.hh
|
||||
intern/asset_library_service.hh
|
||||
intern/asset_storage.hh
|
||||
intern/utils.hh
|
||||
|
@ -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
|
@ -169,13 +169,14 @@ AssetRepresentation &AssetLibrary::add_external_asset(StringRef relative_asset_p
|
||||
std::unique_ptr<AssetMetaData> metadata)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
@ -259,6 +260,12 @@ StringRefNull AssetLibrary::root_path() const
|
||||
Vector<AssetLibraryReference> all_valid_asset_library_refs()
|
||||
{
|
||||
Vector<AssetLibraryReference> result;
|
||||
{
|
||||
AssetLibraryReference library_ref{};
|
||||
library_ref.custom_library_index = -1;
|
||||
library_ref.type = ASSET_LIBRARY_ESSENTIALS;
|
||||
result.append(library_ref);
|
||||
}
|
||||
int i;
|
||||
LISTBASE_FOREACH_INDEX (const bUserAssetLibrary *, asset_library, &U.asset_libraries, i) {
|
||||
if (!BLI_is_dir(asset_library->path)) {
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include "AS_asset_catalog_tree.hh"
|
||||
#include "AS_asset_library.hh"
|
||||
#include "AS_essentials_library.hh"
|
||||
#include "asset_library_service.hh"
|
||||
#include "utils.hh"
|
||||
|
||||
@ -60,6 +61,14 @@ AssetLibrary *AssetLibraryService::get_asset_library(
|
||||
const eAssetLibraryType type = eAssetLibraryType(library_reference.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: {
|
||||
/* 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) :
|
||||
@ -74,12 +83,22 @@ AssetLibrary *AssetLibraryService::get_asset_library(
|
||||
case ASSET_LIBRARY_ALL:
|
||||
return get_asset_library_all(bmain);
|
||||
case ASSET_LIBRARY_CUSTOM: {
|
||||
std::string root_path = root_path_from_library_ref(library_reference);
|
||||
|
||||
if (!root_path.empty()) {
|
||||
return get_asset_library_on_disk(root_path);
|
||||
bUserAssetLibrary *custom_library = find_custom_asset_library_from_library_ref(
|
||||
library_reference);
|
||||
if (!custom_library) {
|
||||
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();
|
||||
}
|
||||
|
||||
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(
|
||||
const AssetLibraryReference &library_reference)
|
||||
{
|
||||
@ -187,16 +215,13 @@ std::string AssetLibraryService::root_path_from_library_ref(
|
||||
return "";
|
||||
}
|
||||
|
||||
BLI_assert(library_reference.type == ASSET_LIBRARY_CUSTOM);
|
||||
BLI_assert(library_reference.custom_library_index >= 0);
|
||||
|
||||
bUserAssetLibrary *user_library = BKE_preferences_asset_library_find_from_index(
|
||||
&U, library_reference.custom_library_index);
|
||||
if (!user_library || !user_library->path[0]) {
|
||||
bUserAssetLibrary *custom_library = find_custom_asset_library_from_library_ref(
|
||||
library_reference);
|
||||
if (!custom_library || !custom_library->path[0]) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return user_library->path;
|
||||
return custom_library->path;
|
||||
}
|
||||
|
||||
void AssetLibraryService::allocate_service_instance()
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <memory>
|
||||
|
||||
struct AssetLibraryReference;
|
||||
struct bUserAssetLibrary;
|
||||
|
||||
namespace blender::asset_system {
|
||||
|
||||
@ -58,6 +59,8 @@ class AssetLibraryService {
|
||||
static void destroy();
|
||||
|
||||
static std::string root_path_from_library_ref(const AssetLibraryReference &library_reference);
|
||||
static bUserAssetLibrary *find_custom_asset_library_from_library_ref(
|
||||
const AssetLibraryReference &library_reference);
|
||||
|
||||
AssetLibrary *get_asset_library(const Main *bmain,
|
||||
const AssetLibraryReference &library_reference);
|
||||
|
@ -8,8 +8,10 @@
|
||||
|
||||
#include "DNA_ID.h"
|
||||
#include "DNA_asset_types.h"
|
||||
#include "DNA_userdef_types.h"
|
||||
|
||||
#include "AS_asset_identifier.hh"
|
||||
#include "AS_asset_library.hh"
|
||||
#include "AS_asset_representation.h"
|
||||
#include "AS_asset_representation.hh"
|
||||
|
||||
@ -17,15 +19,24 @@ namespace blender::asset_system {
|
||||
|
||||
AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier,
|
||||
StringRef name,
|
||||
std::unique_ptr<AssetMetaData> metadata)
|
||||
: identifier_(identifier), is_local_id_(false), external_asset_()
|
||||
std::unique_ptr<AssetMetaData> metadata,
|
||||
const AssetLibrary &owner_asset_library)
|
||||
: identifier_(identifier),
|
||||
is_local_id_(false),
|
||||
owner_asset_library_(&owner_asset_library),
|
||||
external_asset_()
|
||||
{
|
||||
external_asset_.name = name;
|
||||
external_asset_.metadata_ = std::move(metadata);
|
||||
}
|
||||
|
||||
AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier, ID &id)
|
||||
: identifier_(identifier), is_local_id_(true), local_asset_id_(&id)
|
||||
AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier,
|
||||
ID &id,
|
||||
const AssetLibrary &owner_asset_library)
|
||||
: identifier_(identifier),
|
||||
is_local_id_(true),
|
||||
owner_asset_library_(&owner_asset_library),
|
||||
local_asset_id_(&id)
|
||||
{
|
||||
if (!id.asset_data) {
|
||||
throw std::invalid_argument("Passed ID is not an asset");
|
||||
@ -70,11 +81,32 @@ AssetMetaData &AssetRepresentation::get_metadata() const
|
||||
return is_local_id_ ? *local_asset_id_->asset_data : *external_asset_.metadata_;
|
||||
}
|
||||
|
||||
std::optional<eAssetImportMethod> AssetRepresentation::get_import_method() const
|
||||
{
|
||||
if (!owner_asset_library_) {
|
||||
return {};
|
||||
}
|
||||
return owner_asset_library_->import_method_;
|
||||
}
|
||||
|
||||
bool AssetRepresentation::may_override_import_method() const
|
||||
{
|
||||
if (!owner_asset_library_ || !owner_asset_library_->import_method_) {
|
||||
return true;
|
||||
}
|
||||
return owner_asset_library_->may_override_import_method_;
|
||||
}
|
||||
|
||||
bool AssetRepresentation::is_local_id() const
|
||||
{
|
||||
return is_local_id_;
|
||||
}
|
||||
|
||||
const AssetLibrary &AssetRepresentation::owner_asset_library() const
|
||||
{
|
||||
return *owner_asset_library_;
|
||||
}
|
||||
|
||||
} // namespace blender::asset_system
|
||||
|
||||
using namespace blender;
|
||||
@ -87,6 +119,21 @@ const std::string AS_asset_representation_full_path_get(const AssetRepresentatio
|
||||
return identifier.full_path();
|
||||
}
|
||||
|
||||
std::optional<eAssetImportMethod> AS_asset_representation_import_method_get(
|
||||
const AssetRepresentation *asset_handle)
|
||||
{
|
||||
const asset_system::AssetRepresentation *asset =
|
||||
reinterpret_cast<const asset_system::AssetRepresentation *>(asset_handle);
|
||||
return asset->get_import_method();
|
||||
}
|
||||
|
||||
bool AS_asset_representation_may_override_import_method(const AssetRepresentation *asset_handle)
|
||||
{
|
||||
const asset_system::AssetRepresentation *asset =
|
||||
reinterpret_cast<const asset_system::AssetRepresentation *>(asset_handle);
|
||||
return asset->may_override_import_method();
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/** \name C-API
|
||||
* \{ */
|
||||
|
@ -15,18 +15,21 @@
|
||||
|
||||
namespace blender::asset_system {
|
||||
|
||||
AssetRepresentation &AssetStorage::add_local_id_asset(AssetIdentifier &&identifier, ID &id)
|
||||
AssetRepresentation &AssetStorage::add_local_id_asset(AssetIdentifier &&identifier,
|
||||
ID &id,
|
||||
const AssetLibrary &owner_asset_library)
|
||||
{
|
||||
return *local_id_assets_.lookup_key_or_add(
|
||||
std::make_unique<AssetRepresentation>(std::move(identifier), id));
|
||||
std::make_unique<AssetRepresentation>(std::move(identifier), id, owner_asset_library));
|
||||
}
|
||||
|
||||
AssetRepresentation &AssetStorage::add_external_asset(AssetIdentifier &&identifier,
|
||||
StringRef name,
|
||||
std::unique_ptr<AssetMetaData> metadata)
|
||||
std::unique_ptr<AssetMetaData> metadata,
|
||||
const AssetLibrary &owner_asset_library)
|
||||
{
|
||||
return *external_assets_.lookup_key_or_add(
|
||||
std::make_unique<AssetRepresentation>(std::move(identifier), name, std::move(metadata)));
|
||||
return *external_assets_.lookup_key_or_add(std::make_unique<AssetRepresentation>(
|
||||
std::move(identifier), name, std::move(metadata), owner_asset_library));
|
||||
}
|
||||
|
||||
bool AssetStorage::remove_asset(AssetRepresentation &asset)
|
||||
|
@ -35,9 +35,12 @@ class AssetStorage {
|
||||
/** See #AssetLibrary::add_external_asset(). */
|
||||
AssetRepresentation &add_external_asset(AssetIdentifier &&identifier,
|
||||
StringRef name,
|
||||
std::unique_ptr<AssetMetaData> metadata);
|
||||
std::unique_ptr<AssetMetaData> metadata,
|
||||
const AssetLibrary &owner_asset_library);
|
||||
/** See #AssetLibrary::add_external_asset(). */
|
||||
AssetRepresentation &add_local_id_asset(AssetIdentifier &&identifier, ID &id);
|
||||
AssetRepresentation &add_local_id_asset(AssetIdentifier &&identifier,
|
||||
ID &id,
|
||||
const AssetLibrary &owner_asset_library);
|
||||
|
||||
/** See #AssetLibrary::remove_asset(). */
|
||||
bool remove_asset(AssetRepresentation &asset);
|
||||
|
@ -165,7 +165,7 @@ int BLF_load_unique(const char *name)
|
||||
|
||||
/* XXX: Temporarily disable kerning in our main font. Kerning had been accidentally removed from
|
||||
* our font in 3.1. In 3.4 we disable kerning here in the new version to keep spacing the same
|
||||
* (T101506). Enable again later with change of font, placement, or rendering - Harley. */
|
||||
* (#101506). Enable again later with change of font, placement, or rendering - Harley. */
|
||||
if (font && BLI_str_endswith(filepath, BLF_DEFAULT_PROPORTIONAL_FONT)) {
|
||||
font->face_flags &= ~FT_FACE_FLAG_KERNING;
|
||||
}
|
||||
|
@ -271,7 +271,7 @@ struct bPoseChannel *BKE_pose_channel_active_if_layer_visible(struct Object *ob)
|
||||
* In this case the active-selected is an obvious choice when finding the target for a
|
||||
* constraint for eg. however from the users perspective the active pose bone of the
|
||||
* active object is the _real_ active bone, so any other non-active selected bone
|
||||
* is a candidate for being the other selected bone, see: T58447.
|
||||
* is a candidate for being the other selected bone, see: #58447.
|
||||
*/
|
||||
struct bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob);
|
||||
/**
|
||||
|
@ -37,7 +37,7 @@ struct bActionGroup;
|
||||
/* Container for data required to do FCurve and Driver evaluation. */
|
||||
typedef struct AnimationEvalContext {
|
||||
/* For drivers, so that they have access to the dependency graph and the current view layer. See
|
||||
* T77086. */
|
||||
* #77086. */
|
||||
struct Depsgraph *depsgraph;
|
||||
|
||||
/* FCurves and Drivers can be evaluated at a different time than the current scene time, for
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user